package service

import (
	"fmt"
	"strings"
	"time"

	"gitee.com/war2001/NiuMaEasyGo/model"
	"gitee.com/war2001/NiuMaEasyGo/utils"
	"github.com/mssola/user_agent"
	"go.uber.org/zap"
	"gorm.io/gorm"
)

// LoginLogService 登录日志服务实现
type LoginLogService struct {
	db *gorm.DB
}

// NewLoginLogService 创建登录日志服务
func NewLoginLogService(db *gorm.DB) model.LoginLogService {
	return &LoginLogService{
		db: db,
	}
}

// Create 创建登录日志
func (s *LoginLogService) Create(log *model.LoginLog) error {
	return s.db.Create(log).Error
}

// GetByID 根据ID获取登录日志
func (s *LoginLogService) GetByID(id uint) (*model.LoginLog, error) {
	var log model.LoginLog
	err := s.db.Where("id = ?", id).First(&log).Error
	if err != nil {
		return nil, err
	}
	return &log, nil
}

// List 获取登录日志列表
func (s *LoginLogService) List(page, pageSize int, query map[string]interface{}) ([]*model.LoginLog, int64, error) {
	var logs []*model.LoginLog
	var total int64

	db := s.db.Model(&model.LoginLog{})

	// 构建查询条件
	for k, v := range query {
		if v != nil && v != "" {
			switch k {
			case "username":
				db = db.Where("username LIKE ?", "%"+v.(string)+"%")
			case "login_ip":
				db = db.Where("login_ip LIKE ?", "%"+v.(string)+"%")
			case "login_location":
				db = db.Where("login_location LIKE ?", "%"+v.(string)+"%")
			case "status":
				db = db.Where("status = ?", v)
			case "is_abnormal":
				db = db.Where("is_abnormal = ?", v)
			case "start_time":
				db = db.Where("login_time >= ?", v)
			case "end_time":
				db = db.Where("login_time <= ?", v)
			}
		}
	}

	// 查询总数
	err := db.Count(&total).Error
	if err != nil {
		return nil, 0, err
	}

	// 分页查询
	offset := (page - 1) * pageSize
	err = db.Order("login_time DESC").Offset(offset).Limit(pageSize).Find(&logs).Error
	if err != nil {
		return nil, 0, err
	}

	return logs, total, nil
}

// RecordLoginLog 记录登录日志
func (s *LoginLogService) RecordLoginLog(userID uint, username, loginType, loginIP, userAgent string, status int, msg string) error {
	// 解析User-Agent
	ua := user_agent.New(userAgent)
	browser, version := ua.Browser()
	os := ua.OS()

	// 获取登录位置
	location, err := utils.GetIPLocation(loginIP)
	if err != nil {
		zap.L().Error("获取IP位置信息失败", zap.Error(err))
		location = "未知位置"
	}

	// 创建登录日志
	log := &model.LoginLog{
		UserID:        userID,
		Username:      username,
		LoginType:     loginType,
		LoginIP:       loginIP,
		LoginLocation: location,
		UserAgent:     userAgent,
		Browser:       fmt.Sprintf("%s %s", browser, version),
		OS:            os,
		Status:        status,
		Msg:           msg,
		LoginTime:     time.Now(),
		IsAbnormal:    0, // 默认为正常登录
		AbnormalType:  "",
	}

	// 检测是否异常登录
	if status == 1 { // 只有登录成功才检测异常
		isAbnormal, abnormalType := s.detectAbnormalLogin(userID, loginIP, location)
		log.IsAbnormal = isAbnormal
		log.AbnormalType = abnormalType

		// 更新用户最后登录信息
		if err := s.updateUserLastLogin(userID, loginIP); err != nil {
			zap.L().Error("更新用户最后登录信息失败", zap.Error(err))
		}
	}

	// 保存登录日志
	return s.Create(log)
}

// GetUserLoginLogs 获取用户登录日志
func (s *LoginLogService) GetUserLoginLogs(userID uint, page, pageSize int) ([]*model.LoginLog, int64, error) {
	query := map[string]interface{}{
		"user_id": userID,
	}
	return s.List(page, pageSize, query)
}

// GetRecentLoginLogs 获取最近的登录日志
func (s *LoginLogService) GetRecentLoginLogs(userID uint, limit int) ([]*model.LoginLog, error) {
	var logs []*model.LoginLog
	err := s.db.Where("user_id = ?", userID).
		Order("login_time DESC").
		Limit(limit).
		Find(&logs).Error
	return logs, err
}

// GetAbnormalLoginLogs 获取异常登录日志
func (s *LoginLogService) GetAbnormalLoginLogs(page, pageSize int) ([]*model.LoginLog, int64, error) {
	query := map[string]interface{}{
		"is_abnormal": 1,
	}
	return s.List(page, pageSize, query)
}

// ClearLoginLogs 清理指定天数前的登录日志
func (s *LoginLogService) ClearLoginLogs(days int) error {
	if days <= 0 {
		return fmt.Errorf("清理天数必须大于0")
	}

	// 计算截止时间
	cutoffTime := time.Now().AddDate(0, 0, -days)

	// 删除截止时间之前的日志
	result := s.db.Where("login_time < ?", cutoffTime).Delete(&model.LoginLog{})
	if result.Error != nil {
		return result.Error
	}

	zap.L().Info("清理登录日志完成", zap.Int64("count", result.RowsAffected), zap.Int("days", days))
	return nil
}

// detectAbnormalLogin 检测异常登录
func (s *LoginLogService) detectAbnormalLogin(userID uint, loginIP, location string) (int, string) {
	// 获取最近一次登录记录
	var lastLog model.LoginLog
	err := s.db.Where("user_id = ? AND status = 1", userID).
		Order("login_time DESC").
		First(&lastLog).Error

	// 如果没有找到记录，说明是首次登录，不算异常
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			return 0, ""
		}
		zap.L().Error("查询最近登录记录失败", zap.Error(err))
		return 0, ""
	}

	// 检测异地登录
	if lastLog.LoginLocation != "" && location != "" &&
		lastLog.LoginLocation != "未知位置" && location != "未知位置" &&
		!strings.Contains(location, lastLog.LoginLocation) &&
		!strings.Contains(lastLog.LoginLocation, location) {
		return 1, "异地登录"
	}

	// 检测短时间内多次登录
	// 如果上次登录时间在30分钟内且IP不同，可能是异常
	if time.Since(lastLog.LoginTime) < 30*time.Minute && lastLog.LoginIP != loginIP {
		return 1, "短时间内不同IP登录"
	}

	// 检测频繁登录
	var count int64
	s.db.Model(&model.LoginLog{}).
		Where("user_id = ? AND login_time > ? AND login_ip != ?",
			userID, time.Now().Add(-1*time.Hour), loginIP).
		Count(&count)

	if count > 5 {
		return 1, "频繁登录"
	}

	return 0, ""
}

// updateUserLastLogin 更新用户最后登录信息
func (s *LoginLogService) updateUserLastLogin(userID uint, loginIP string) error {
	return s.db.Model(&model.User{}).
		Where("id = ?", userID).
		Updates(map[string]interface{}{
			"last_login_at": time.Now(),
			"last_login_ip": loginIP,
		}).Error
}
